import { BadRequestException, Inject, Injectable } from '@nestjs/common';
import { ConfigType } from '@nestjs/config';
import { JwtService } from '@nestjs/jwt';
import jwtConfig from 'config/jwt.config';
import { SignInDto } from './dto/sign-in.dto';
import { InjectRepository } from '@nestjs/typeorm';
import { User } from '../user/entities/user.entity';
import { Repository } from 'typeorm';
import { SignUpDto } from './dto/sign-up.dto';
import { HashingService } from './hashing.service';
import { GlobalAPI } from 'src/common/typings/global';

@Injectable()
export class AuthService {
  @Inject(JwtService)
  private readonly jwtService: JwtService;

  @Inject(jwtConfig.KEY)
  private readonly jwtConfiguration: ConfigType<typeof jwtConfig>;

  @InjectRepository(User)
  private readonly userRepository: Repository<User>;

  @Inject(HashingService)
  private readonly hashingService: HashingService;

  async generateTokens(user: User) {
    const token = await this.signToken<Partial<GlobalAPI.PayloadProps>>(
      user.id,
      {
        username: user.username,
      },
    );
    return { token };
  }

  private async signToken<T>(userId: number, payload?: T) {
    return await this.jwtService.signAsync(
      {
        sub: userId,
        ...payload,
      },
      {
        secret: this.jwtConfiguration.secret,
        audience: this.jwtConfiguration.audience,
        issuer: this.jwtConfiguration.issuer,
        expiresIn: this.jwtConfiguration.accessTokenTtl,
      },
    );
  }

  async signIn(signInDto: SignInDto) {
    const { username, password } = signInDto;

    const user = await this.userRepository.findOne({ where: { username } });
    if (!user) throw new BadRequestException('用户不存在');

    const isEqual = await this.hashingService.compare(password, user.password);
    if (!isEqual) throw new BadRequestException('密码不正确');

    return await this.generateTokens(user);
  }

  async signUp(signUpDto: SignUpDto) {
    const { username, password } = signUpDto;

    const existingUser = await this.userRepository.findOne({
      where: [{ username }],
    });
    if (existingUser) throw new BadRequestException('用户已存在');

    const hashedPassword = await this.hashingService.hash(password); // +
    const user = this.userRepository.create({
      ...signUpDto,
      password: hashedPassword,
    }); // +
    return this.userRepository.save(user);
  }
}
